﻿#region Libraries

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using JBeamLibrary.Events;
using JBeamLibrary.Tools;
using JBeamLibrary.VehicleParts.Collections;
using JBeamLibrary.VehicleParts.Elements;
using JBeamLibrary.VehicleParts.Groups;
using Newtonsoft.Json.Linq;

#endregion

namespace JBeamLibrary.VehicleParts
{
    public class VehiclePart
    {
        #region Fields

        private readonly string _name;
        private readonly VehicleFile _file;
        private readonly List<string> _authors = new List<string>();

        private readonly SlotCollection _slots = new SlotCollection();
        private readonly Ropables _ropables = new Ropables();
        private readonly Nodes _nodes = new Nodes();
        private readonly Beams _beams = new Beams();
        private readonly Flexbodies _flexbodies = new Flexbodies();
        private readonly InternalCameras _internalCameras = new InternalCameras();
        private readonly HubWheels _hubWheels = new HubWheels();
        private readonly Hydros _hydros = new Hydros();
        private readonly Props _props = new Props();
        private readonly GlowMap _glowMap = new GlowMap();
        private readonly Triangles _triangles = new Triangles();
        private readonly EngineTorque _engineTorque = new EngineTorque();
        private readonly Ties _ties = new Ties();
        private readonly DifferentialCollection _differentials = new DifferentialCollection();

        private float _dragCoef = float.MinValue;

        public BeamScales _beamScales = new BeamScales();
        public NodeScales _nodeScales = new NodeScales();
        public CollisionValues _collisions = new CollisionValues();

        /* IN TEST */
        private readonly NodeSection _nodeSection;
        private readonly BeamSection _beamSection;
        private readonly TriangleSection _triangleSection;
        private readonly HydroSection _hydroSection;
        private readonly HubWheelSection _hubWheelSection;
        private readonly InternalCameraSection _internalCameraSection;
        private readonly TieSection _tieSection;
        private readonly FlexbodySection _flexbodySection;
        private readonly PropSection _propSection;
        private readonly ThrusterSection _thrusterSection;

        #endregion

        #region Properties

        /// <summary>Gets a value indicating whether this part is the main part of the file</summary>
        public bool IsMainPart
        {
            get { return Name.SafeEquals(File.Name); }
        }

        /// <summary>Gets the name of this part</summary>
        public string Name { get { return _name; } }

        /// <summary>Gets or sets the vehicle part description</summary>
        public string Description { get; set; }

        /// <summary>Gets the authors</summary>
        public IEnumerable<string> Authors { get { return _authors; } }

        /// <summary>Gets the lsit of authors in a string</summary>
        public string AuthorsString { get { return string.Join(", ", Authors); } }

        /// <summary>Gets the vehicle file this part belongs to</summary>
        public VehicleFile File { get { return _file; } }

        /// <summary>Gets the path to the vehicle part file</summary>
        public string FilePath
        {
            get { return File.FilePath; }
        }

        /// <summary>Gets or sets the slot type this vehicle part should belong to</summary>
        public string SlotType { get; set; }

        /// <summary>Gets or sets the drag coefficient</summary>
        public float DragCoef { get { return _dragCoef; } set { _dragCoef = value; } }

        /// <summary>Gets or sets the collision values</summary>
        public CollisionValues Collisions
        {
            get { return Config.EnableGlobalModifiers ? File.Parent.Collisions : _collisions; }
            set
            {
                if (Config.EnableGlobalModifiers)
                    File.Parent.Collisions = value;
                else
                    _collisions = value;
            }
        }

        /// <summary>Gets the beam scales</summary>
        public BeamScales BeamScales
        {
            get { return Config.EnableGlobalModifiers ? File.Parent.BeamScales : _beamScales; }
            set
            {
                if (Config.EnableGlobalModifiers)
                    File.Parent.BeamScales = value;
                else
                    _beamScales = value;
            }
        }

        /// <summary>Gets the node scales</summary>
        public NodeScales NodeScales
        {
            get { return Config.EnableGlobalModifiers ? File.Parent.NodeScales : _nodeScales; }
            set
            {
                if (Config.EnableGlobalModifiers)
                    File.Parent.NodeScales = value;
                else
                    _nodeScales = value;
            }
        }

        /// <summary>Gets the ref nodes</summary>
        public RefNodes RefNodes { get; set; }

        /// <summary>Gets the external camera</summary>
        public Camera CameraExternal { get; private set; }

        /// <summary>Gets the slots collection</summary>
        public SlotCollection Slots { get { return _slots; } }

        /// <summary>Gets the ropables group</summary>
        public Ropables Ropables { get { return _ropables; } }

        /// <summary>Gets the nodes group</summary>
        public Nodes Nodes { get { return _nodes; } }

        /// <summary>Gets the beams group</summary>
        public Beams Beams { get { return _beams; } }

        /// <summary>Gets the hub wheels group</summary>
        public HubWheels HubWheels { get { return _hubWheels; } }

        /// <summary>Gets the hydros group</summary>
        public Hydros Hydros { get { return _hydros; } }

        /// <summary>Gets the flexbodies group</summary>
        public Flexbodies Flexbodies { get { return _flexbodies; } }

        /// <summary>Gets the internal cameras</summary>
        public InternalCameras InternalCameras { get { return _internalCameras; } }

        /// <summary>Gets the props group</summary>
        public Props Props { get { return _props; } }

        /// <summary>Gets the glow map</summary>
        public GlowMap GlowMap { get { return _glowMap; } }

        /// <summary>Gets the triangles</summary>
        public Triangles Triangles { get { return _triangles; } }

        /// <summary>Gets the engine properties</summary>
        public Engine Engine { get; private set; }

        /// <summary>Gets the engine torque</summary>
        public EngineTorque EngineTorque { get { return _engineTorque; } }

        /// <summary>Gets the differentials</summary>
        public DifferentialCollection Differentials { get { return _differentials; } }

        /// <summary>Gets the ties</summary>
        public Ties Ties { get { return _ties; } }



        /* IN TEST */

        public NodeSection NodeSection { get { return _nodeSection; } }

        public BeamSection BeamSection { get { return _beamSection; } }

        public TriangleSection TriangleSection { get { return _triangleSection; } }

        public HydroSection HydroSection { get { return _hydroSection; } }

        public HubWheelSection HubWheelSection { get { return _hubWheelSection; } }

        public InternalCameraSection InternalCameraSection { get { return _internalCameraSection; } }

        public TieSection TieSection { get { return _tieSection; } }

        public FlexbodySection FlexbodySection { get { return _flexbodySection; } }

        public PropSection PropSection { get { return _propSection; } }

        public ThrusterSection ThrusterSection { get { return _thrusterSection; } }

        #endregion

        #region CTORs

        public VehiclePart(string name, VehicleFile file)
        {
            _name = name;
            _file = file;

            SlotType = "main";
            RefNodes = new RefNodes();
            CameraExternal = new Camera();
            Engine = new Engine();

            _nodeSection = new NodeSection(this);
            _beamSection = new BeamSection(this);
            _triangleSection = new TriangleSection(this);
            _hydroSection = new HydroSection(this);
            _hubWheelSection = new HubWheelSection(this);
            _internalCameraSection = new InternalCameraSection(this);
            _tieSection = new TieSection(this);
            _flexbodySection = new FlexbodySection(this);
            _propSection = new PropSection(this);
            _thrusterSection = new ThrusterSection(this);

            InitializeSections();
        }

        #endregion

        #region Events

        protected void NodePropertyChanged(object sender, ElementPropertyChangedEventArgs e)
        {
            /* Cast sender as node */
            var node = sender as Node;
            if (node == null) return;

            /* If property is the ID, update required elements */
            if (e.PropertyName.Equals("id", StringComparison.InvariantCultureIgnoreCase))
                File.Parent.UpdateNodeLinks((string)e.OldValue, (string)e.NewValue);
        }

        #endregion

        #region Methods

        private void InitializeSections()
        {
            /* Setup events */
            _nodeSection.ElementPropertyChanged += NodePropertyChanged;
        }

        public void AddAuthor(string name)
        {
            if (_authors.Contains(name)) return;
            _authors.Add(name);
        }

        public void AddAuthors(IEnumerable<string> authors)
        {
            _authors.AddRange(authors.Where(author => !_authors.Contains(author)));
        }

        public void RemoveAuthor(string name)
        {
            _authors.Remove(name);
        }

        public void ResetAuthors()
        {
            _authors.Clear();
        }

        public override string ToString()
        {
            return string.Format("{0} by {1}", Description, AuthorsString);
        }

        #endregion
    }
}